#include "PS2_KB.h"
#include "hid.h"

// PS2编码表
//  下标：序列号0
//  值：对应的PS/2扫描码
//      0x00：不支持
//      0xE0：扩展码——需要另外查表
const uint8_t PS2_SET2_MAKE[] = {
    0x00, // 00 N/A
    0x1C, // 01 A
    0x32, // 02 B
    0x21, // 03 C
    0x23, // 04 D
    0x24, // 05 E
    0x2B, // 06 F
    0x34, // 07 G
    0x33, // 08 H
    0x43, // 09 I
    0x3B, // 10 J
    0x42, // 11 K
    0x4B, // 12 L
    0x3A, // 13 M
    0x31, // 14 N
    0x44, // 15 O
    0x4D, // 16 P
    0x15, // 17 Q
    0x2D, // 18 R
    0x1B, // 19 S
    0x2C, // 20 T
    0x3C, // 21 U
    0x2A, // 22 V
    0x1D, // 23 W
    0x22, // 24 X
    0x35, // 25 Y
    0x1A, // 26 Z
    0x45, // 27 0
    0x16, // 28 1
    0x1E, // 29 2
    0x26, // 30 3
    0x25, // 31 4
    0x2E, // 32 5
    0x36, // 33 6
    0x3D, // 34 7
    0x3E, // 35 8
    0x46, // 36 9
    0x0E, // 37 ` ~    JPN 半角/全角|汉字
    0x4E, // 38 - _    JPN - =
    0x55, // 39 = +    JPN ^ ~
    0x5D, // 40 \ |
    0x66, // 41 backspace
    0x29, // 42 space
    0x0D, // 43 tab
    0x58, // 44 caps lock
    0x12, // 45 L shift
    0x14, // 46 L ctrl
    0xE0, // 47 L WIN
    0x11, // 48 L Alt
    0x59, // 49 R shift
    0xE0, // 50 R ctrl
    0xE0, // 51 R WIN
    0xE0, // 52 R Alt
    0xE0, // 53 application
    0x5A, // 54 return
    0x76, // 55 Esc
    0x05, // 56 F1
    0x06, // 57 F2
    0x04, // 58 F3
    0x0C, // 59 F4
    0x03, // 60 F5
    0x0B, // 61 F6
    0x83, // 62 F7
    0x0A, // 63 F8
    0x01, // 64 F9
    0x09, // 65 F10
    0x78, // 66 F11
    0x07, // 67 F12
    0xE0, // 68 print screen
    0x7E, // 69 scroll lock
    0xE0, // 70 pause
    0x54, // 71 [ {     JPN @ ·
    0xE0, // 72 insert
    0xE0, // 73 home
    0xE0, // 74 page up
    0xE0, // 75 del
    0xE0, // 76 end
    0xE0, // 77 page down
    0xE0, // 78 up
    0xE0, // 79 left
    0xE0, // 80 down
    0xE0, // 81 right
    0x77, // 82 num lock
    0xE0, // 83 num /
    0x7C, // 84 num *
    0x7B, // 85 num -
    0x79, // 86 num +
    0xE0, // 87 num enter
    0x71, // 88 num . del
    0x70, // 89 num 0
    0x69, // 90 num 1
    0x72, // 91 num 2
    0x7A, // 92 num 3
    0x6B, // 92 num 4
    0x73, // 94 num 5
    0x74, // 95 num 6
    0x6C, // 96 num 7
    0x75, // 97 num 8
    0x7D, // 98 num 9
    0x5B, // 99 ] }      JPN [ {
    0x4C, // 100 ; :     JPN ; +
    0x52, // 101 ' "     JPN : *
    0x41, // 102 , <
    0x49, // 103 . >
    0x4A, // 104 / ?
    0x5D, // 105
    0x51, // 106         JPN \ -
    0x13, // 107         JPN 输入方式变换
    0x6A, // 108         JPN 羊 |
    0x64, // 109         JPN 变换
    0x67, // 110         JPN 无变换
    0x00, // 111 N/A
    0x00, // 112 N/A
    0x00, // 113 N/A
    0x00, // 114 N/A
    0x00, // 115 N/A
    0x00, // 116 N/A
    0x00, // 117 N/A
    0x00, // 118 N/A
    0x00, // 119 N/A
    0xE0, // 120 power
};

// 机打速率表 (ms)
const uint16_t PS2_KeyRepeatRate[] = {
    500, // 0x00  2.0cps
    476, // 0x01  2.1cps
    434, // 0x02  2.3cps
    400, // 0x03  2.5cps
    370, // 0x04  2.7cps
    333, // 0x05  3.0cps
    303, // 0x06  3.3cps
    270, // 0x07  3.7cps
    250, // 0x08  4.0cps
    232, // 0x09  4.3cps
    217, // 0x0A  4.6cps
    200, // 0x0B  5.0cps
    181, // 0x0C  5.5cps
    166, // 0x0D  6.0cps
    149, // 0x0E  6.7cps
    133, // 0x0F  7.5cps
    125, // 0x10  8.0cps
    116, // 0x11  8.6cps
    108, // 0x12  9.2cps
    100, // 0x13  10.0cps
    91,  // 0x14  10.9cps
    83,  // 0x15  12.0cps
    75,  // 0x16  13.3cps
    66,  // 0x17  15.0cps
    62,  // 0x18  16.0cps
    58,  // 0x19  17.1cps
    54,  // 0x1A  18.5cps
    50,  // 0x1B  20.0cps
    45,  // 0x1C  21.8cps
    41,  // 0x1D  24.0cps
    37,  // 0x1E  26.7cps
    33   // 0x1F  30.0cps
};

// 机打延时表 (ms)
const uint16_t PS2_KeyDelay[] = {
    250, // 0x00  250ms
    500, // 0x01  500ms
    750, // 0x02  750ms
    1000 // 0x03  1000ms
};

extern _HID_KB_INFO HID_KB_INFO;
// #pragma  NOAREGS
/*******************************************************************************
 * Function Name  : InitPS2
 * Description    : 初始化PS2设备,串口默认引脚 P26 P27
 * Input          : None
 * Output         : None
 * Return         : None
 *******************************************************************************/
PS2_KB::PS2_KB(int clk, int d) : PS2_Client(clk, d) {
    HID_KB_INFO.Enable = 0;
}

/*******************************************************************************
 * Function Name  : checkChange
 * Description    : 比较按键变化，生产ps/2编码
 * Input          : None
 * Output         : None
 * Return         : None
 *******************************************************************************/
void PS2_KB::checkChange(void) {
    if (!HID_KB_INFO.Enable) {
        return;
    }

    // 比较所有120个按键
    for (int i = 0; i < 120; i++) {
        if (HID_KB_INFO.KeyStatus[i] == 0 && HID_KB_INFO.KeyStatusTmp[i] == 1) {
            // 按下
            copy_code(i, 1);
        } else if (HID_KB_INFO.KeyStatus[i] == 1 && HID_KB_INFO.KeyStatusTmp[i] == 0) {
            // 释放
            copy_code(i, 0);
        }
        HID_KB_INFO.KeyStatus[i] = HID_KB_INFO.KeyStatusTmp[i];
    }

    // 检查机打按键，若到时则发送
    if (!HID_KB_INFO.KeyRepeat) {
        return;
    }

    if (HID_KB_INFO.KeyRepeatRateCnt == 0 && HID_KB_INFO.KeyDelayCnt == 0) { //
        // 重置机打频率计数
        HID_KB_INFO.KeyRepeatRateCnt = HID_KB_INFO.KeyRepeatRate;

        // 机打指令进缓存
        copy_code(HID_KB_INFO.KeyRepeat, 1);
    }
}

/*******************************************************************************
 * Function Name  : copy_code
 * Description    : 将编码复制到缓存（循环储存）
 * Input          : index   PS/2扫描码序列号
 *                : type    0:断码  1：通码
 * Output         : None
 * Return         : None
 * 注： PS2_TX_E(UINT8) 范围是0~255，正好用来循环储存PS2_TXBuffer[256]而不用担心溢出
 *******************************************************************************/
void PS2_KB::copy_code(uint8_t index, uint8_t type) {
    uint8_t c = 0;

    // 转换为PS/2扫描码
    c = PS2_SET2_MAKE[index];
    if (c == 0xE0) {

        switch (index) {
        case 47: // L GUI
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x1F);
            break;
        case 50: // R Ctrl
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x14);
            break;
        case 51: // R GUI
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x27);
            break;
        case 52: // R Alt
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x11);
            break;
        case 53: // application
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x2F);
            break;
        case 68: // print screen
            if (type) {
                writeBuffer(0xE0);
                writeBuffer(0x12);
                writeBuffer(0xE0);
                writeBuffer(0x7C);
            } else {
                writeBuffer(0xE0);
                writeBuffer(0xF0);
                writeBuffer(0x7C);
                writeBuffer(0xE0);
                writeBuffer(0xF0);
                writeBuffer(0x12);
            }
            break;
        case 70: // pause
            if (type) {
                writeBuffer(0xE1);
                writeBuffer(0x14);
                writeBuffer(0x77);
                writeBuffer(0xE1);
                writeBuffer(0xF0);
                writeBuffer(0x14);
                writeBuffer(0xF0);
                writeBuffer(0x77);
            }
            break;
        case 72: // insert
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x70);
            break;
        case 73: // home
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x6C);
            break;
        case 74: // page up
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x7D);
            break;
        case 75: // del
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x71);
            break;
        case 76: // end
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x69);
            break;
        case 77: // page down
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x7A);
            break;
        case 78: // up
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x75);
            break;
        case 79: // left
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x6B);
            break;
        case 80: // down
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x72);
            break;
        case 81: // right
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x74);
            break;
        case 83: // num /
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x4A);
            break;
        case 87: // num enter
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x5A);
            break;
        case 120: // power
            writeBuffer(0xE0);
            if (!type) {
                writeBuffer(0xF0);
            }
            writeBuffer(0x37);
            break;
        }
    } else {
        if (type) {
            // 1：通码
            writeBuffer(c);

        } else {
            // 0:断码
            writeBuffer(0xF0);
            writeBuffer(c);
        }
    }
}

// 设备复位
void PS2_KB::setDefault() {
    // 初始化键盘
    HID_KB_INFO.LED = 0;                                                   //
    HID_KB_INFO.KeyRepeat = 0;                                             // 机打按键
    HID_KB_INFO.KeyRepeatRate = PS2_KeyRepeatRate[0x14];                   // 机打频率 —— 默认10.9cps
    HID_KB_INFO.KeyDelay = PS2_KeyDelay[0x01];                             // 机打延时 —— 默认500ms
    HID_KB_INFO.KeyRepeatRateCnt = HID_KB_INFO.KeyRepeatRate;              // 机打频率计数
    HID_KB_INFO.KeyDelayCnt = HID_KB_INFO.KeyDelay;                        // 机打延时计数
    memset(HID_KB_INFO.KeyStatus, 0, sizeof(HID_KB_INFO.KeyStatus));       // 记录每个按键当前状态 0：释放， 1按下
    memset(HID_KB_INFO.KeyStatusTmp, 0, sizeof(HID_KB_INFO.KeyStatusTmp)); // 按键的新状态 0：释放， 1按下
    memset(HID_KB_INFO.Keymode, 0, sizeof(HID_KB_INFO.Keymode));           // 按键的新状态 0：释放， 1按下

    PS2_Client::setDefault();
}

uint8_t toHIDCodeLED(uint8_t led) {
    // uint8_t s = 0;
    // if (led & KB_LED_NUM_LOCK) {
    //     s |= HID_LED_NUM_LOCK;
    // }

    // if (led & KB_LED_CAPS_LOCK) {
    //     s |= HID_LED_CAPS_LOCK;
    // }

    // if (led & KB_LED_SCSROLL_LOCK) {
    //     s |= HID_LED_SCSROLL_LOCK;
    // }
    // return s;
}

/*******************************************************************************
 * Function Name  : executeCmd
 * Description    : 接收和执行指令
 * Input          : None
 * Output         : None
 * Return         : None
 *******************************************************************************/
bool PS2_KB::executeCmd(uint8_t cmd) {
    uint8_t para;
    switch (cmd) {
    case 0xED: // 设置键盘LED
    case 0xF0: // 设置或查询编码集合
    case 0xF3: // 设置键盘机打速率和延时
        // 双字节指令，第一周期只回送 0xFA
        sendByte(0xFA);

        // 读取第二字节
        while (!readData(para))
            ;

        printf("para[x%02X]\n", para);
        break;
    }

    switch (cmd) {
    case 0xED: // 设置键盘LED
        HID_KB_INFO.LED = para;
        sendByte(0xFA); // 回复
        //hid_setup(1, toHIDCodeLED(HID_KB_INFO.LED));
        break;
    case 0xF0: // 设置或查询编码集合
        if (para) {
            sendByte(0xFA); // 回复
        } else {
            sendByte(0x02);
            ; // 回复 —— 使用第二套编码集
        }
        break;
    case 0xF2: // 询问device id
        sendByte(0xFA);
        sendByte(0xAB);
        sendByte(0x83);
        break;
    case 0xF3: // 设置键盘机打速率和延时
        // HID_KB_INFO.KeyRepeatRate = PS2_KeyRepeatRate[para & 0x1F];    // 机打频率 —— 默认10.9cps
        para >>= 5;
        HID_KB_INFO.KeyDelay = PS2_KeyDelay[para & 0x03]; // 机打延时 —— 默认500ms

        sendByte(0xFA); // 回复
        break;
    case 0xF4: // 使能键盘
        HID_KB_INFO.Enable = 1;
        sendByte(0xFA); // 回复
        break;
    case 0xF5: // 禁止键盘
        HID_KB_INFO.Enable = 0;
        sendByte(0xFA);  // 回复
        clearTXBuffer(); // 清空缓存——不发送
        break;
    case 0xF6:                                               // 设置缺省
        HID_KB_INFO.KeyRepeatRate = PS2_KeyRepeatRate[0x14]; // 机打频率 —— 默认10.9cps
        HID_KB_INFO.KeyDelay = PS2_KeyDelay[0x01];           // 机打延时 —— 默认500ms
        memset(HID_KB_INFO.Keymode, 0, sizeof(HID_KB_INFO.Keymode));
        sendByte(0xFA);  // 回复
        clearTXBuffer(); // 清空缓存——不发送
        break;
    case 0xF7:                                                          // 设置左右按键的发送方法
        memset(HID_KB_INFO.Keymode, 0x02, sizeof(HID_KB_INFO.Keymode)); // 不发送断码
        sendByte(0xFA);                                                 // 回复
        clearTXBuffer();                                                // 清空缓存——不发送
        break;
    case 0xF8:                                                          // 设置左右按键的发送方法
        memset(HID_KB_INFO.Keymode, 0x01, sizeof(HID_KB_INFO.Keymode)); // 不发送机打
        sendByte(0xFA);                                                 // 回复
        clearTXBuffer();                                                // 清空缓存——不发送
        break;
    case 0xF9:                                                          // 设置左右按键的发送方法
        memset(HID_KB_INFO.Keymode, 0x03, sizeof(HID_KB_INFO.Keymode)); // 不发送断码和机打
        sendByte(0xFA);                                                 // 回复
        clearTXBuffer();                                                // 清空缓存——不发送
        break;
    case 0xFA:                                                       // 复位所有键盘的默认发送方式
        memset(HID_KB_INFO.Keymode, 0, sizeof(HID_KB_INFO.Keymode)); // 按键的新状态 0：释放， 1按下
        sendByte(0xFA);                                              // 回复
        break;
    case 0xFF:           // 复位键盘
        sendByte(0xFA);  // 回复成功
        clearTXBuffer(); // 清空缓存——不发送

        //hid_setup(1, 0x07); // 点亮所有LED
        setDefault();
        HID_KB_INFO.Enable = 1;
        delay(450);
        //hid_setup(1, 0x00); // 熄灭所有LED

        sendByte(0xAA); // 回复成功

        break;
    default:
        PS2_Client::executeCmd(cmd); // 回复
        break;
    }
}
